算法系列——八皇后问题

public class Queen {
    private final int size;
    private int[] location;
    private int[] columnOccupied;
    private int[] lineOccupied;            //对角线
    private int[] reverseLineOccupied;     //反对角线
    private static int solveCount;
    private static final int locationOccupied = 1;
    private static final int unLocationOccupied = 0;
    
    public Queen(int size){
        this.size = size;
        location = new int[size];
        columnOccupied = new int[size];
        lineOccupied= new int[2*size];
        reverseLineOccupied = new int[2*size];
    }
    
    public void printLocation(){
        System.out.println("第"+solveCount+"方法");
        for(int i=0;i<size;i++){
            System.out.println("行"+i+"列"+location[i]);
        }
    }
    
    private boolean isOccupied(int i,int j){
        return(columnOccupied[j]==locationOccupied)||                   //列被占据
            (lineOccupied[i-j-1+size]==locationOccupied)||              //斜线被占据
                (reverseLineOccupied[i+j]==locationOccupied);          //反斜线被占
    }
    
    public void setLocation(int i,int j,int flag){
        columnOccupied[j] = flag;
        lineOccupied[i-j-1+size] = flag;
        reverseLineOccupied[i+j] = flag;
    }
    public void place(int i){
        for(int j=0;j<size;j++){
            if(!isOccupied(i,j)){
                location[i] = j;
                setLocation(i,j,locationOccupied);
             
                if(i<size-1){
                    place(i+1);
                 
                }else{
                    solveCount++;
                    printLocation();
                
                }
                setLocation(i,j,unLocationOccupied);
            }
        }
    }
    public  void start(int i){
        place(i);
    }

    public static void main(String[] args){
          new Queen(8).start(0);
         
        
    }
     
}

 代码来自   http://blog.163.com/jiaze_yao@126/blog/static/250344322011273515769/  ,作者写的真漂亮。

 

八皇后问题在放置每个皇后时要满足没有别的皇后在同一条线上,包括同一列(j),同一行(i),同一斜线(i-j-1+size),同一反斜线(i+j)。满足这四个条件就可以放置。

第一步:从第0行开始,place(0),查看第0行可以放置的列,方法是将所有的列遍历一遍,碰见第一个位置满足上述条件的就放进去,然后改变此位置的状态。

第二步:在place(0)中,递归调用place(1),在place(1)中,调用place(2)。。。这样,当所有位置放置完成,输出一种放置方法;另一种情况是到了后期无法放置;这两种情况发生后,程序都会取消这一步的操作,返回上一步,继续把没遍历完的j遍历完成,搜索所有可能情况。

比如当i=7时,如果j=2满足条件,由于i已达最大,所以可以将所有位置信息输出,输出之后,将i=7,j=2取消,从j=3开始,再次寻找合适情况。这样,就可以把i=7的所有可能j的情况都遍历到。完成后,退回上一步。

此时i=6,假设是以i=6,j=1的情况进入的i=7,那么就从i=6,j=2开始遍历j,满足时,再次进入i=7,j再从1开始。这样,把i=6的所有情况考虑完之后,退回i=5.这种方法称为回溯法。

 

回溯法(英语:backtracking)是穷尽搜索算法(英语:Brute-force search)中的一种。

回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两 种情况:

    * 找到一个可能存在的正确的答案
    * 在尝试了所有可能的分步方法后宣告该问题没有答案

在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算。

 

posted @ 2015-05-04 13:00  HugoFly  阅读(927)  评论(0编辑  收藏  举报